package cn.ym.ymcc.service.impl;

import cn.ym.ymcc.constant.CustomConstant;
import cn.ym.ymcc.domain.Course;
import cn.ym.ymcc.dto.RegisterCodeRedis;
import cn.ym.ymcc.dto.VerifyCodeDto;
import cn.ym.ymcc.exception.BusinessException;
import cn.ym.ymcc.feign.CourseServerFeign;
import cn.ym.ymcc.feign.UserFeignClient;
import cn.ym.ymcc.result.JSONResult;
import cn.ym.ymcc.service.IMessageSmsService;
import cn.ym.ymcc.service.IVerifyCodeService;
import cn.ym.ymcc.utils.AssertUtil;
import cn.ym.ymcc.utils.EmailUtils;
import cn.ym.ymcc.utils.StrUtils;
import cn.ym.ymcc.utils.VerifyCodeUtils;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    @Autowired
    private UserFeignClient userFeignClient;
    @Autowired
    private CourseServerFeign courseServerFeign;
    @Autowired
    private IMessageSmsService messageSmsService;

    /**
     * //获取图形验证码
     * @param key
     * @return
     */
    @Override
    public String getImageCode(String key) {
        //1.通过StrUilts生成4位的图形验证码code - 字符串
        String code = StrUtils.getComplexRandomString(4);
        //2.将key和图形验证码code保存到redis，5分钟后过期
        redisTemplate.opsForValue().set(key,code,5,TimeUnit.MINUTES);
        //3.将图形验证码写到图片中并且使用base64编码 - 调用VerifyCodeUtils
        String base64Str = VerifyCodeUtils.verifyCode(115, 40, code);
       return base64Str;
    }

    /**
     * 手机验证码
     * @param dto
     */
    @Override
    public void sendSmsCode(VerifyCodeDto dto) {
        // 发送验证码的逻辑：
        /**1.空值校验*/
        //用户输入
        String imageCode = dto.getImageCode();
        //图形验证码
        String imageCodeKey = dto.getImageCodeKey();
        //电话号
        String mobile = dto.getMobile();
        //校验前端传递的参数 不能为空和是否注册过
        AssertUtil.isNotEmpty(mobile,"电话不能为空！！！");

        /**2..校验图像验证码*/
        Object obj = redisTemplate.opsForValue().get(imageCodeKey);
        //2.1校验 - 图形验证码是否过期，是否正确
//        if (obj == null){
//            throw new BusinessException("图形验证码过期!");
//        }
        AssertUtil.isNotNull(obj,"图形验证码过期");
        //2.2校验输入的图形验证码是否正确
        if (!imageCode.equalsIgnoreCase(obj.toString())){
            throw new BusinessException("图形验证码错误!");
        }

        /**3.校验 手机是否注册过*/
        JSONResult jsonResult = userFeignClient.findByPhone(mobile);
        if (jsonResult.isSuccess() == false){
            throw new BusinessException(jsonResult.getMessage());
        }
        //3.1判断jsonResult不为null
        AssertUtil.isTrue(jsonResult.isSuccess(),"用户服务异常!!!");
        //3.2判断data为null
        AssertUtil.isNull(jsonResult.getData(),"该手机号码已注册，请直接登录!");

        //黑名单:Redis实现一个手机号 1 分钟内最多只能发3次，
        Object o = redisTemplate.opsForValue().get(mobile);
        if (o == null){
            redisTemplate.opsForValue().set(mobile,0,1,TimeUnit.MINUTES);
        }
        Integer num = Integer.valueOf(redisTemplate.opsForValue().get(mobile).toString());
        num++;
        redisTemplate.opsForValue().set(mobile,num,1,TimeUnit.MINUTES);
        if (num > 3){
            throw new BusinessException("该号码今日注册次数已达上限，请明日再来！");
        }


        /**4.准备一个验证码*/
        String code = StrUtils.getRandomString(6);
        //3.1存放在redis里面的key
        String key = "sms:"+dto.getMobile();
        //3.2检查redis里面的key是否存放过
        RegisterCodeRedis codeRedis = (RegisterCodeRedis) redisTemplate.opsForValue().get(key);
        if (codeRedis != null){//第一次发送 or 过期了
            //检查上次发送的时间间隔  --（当前时间-上一次的时间）/1000<60
            if ((System.currentTimeMillis() - codeRedis.getTime())/1000<1){
                throw new BusinessException("请勿重复发送验证码!");
            }else {//没有过期，后续获取
                code = codeRedis.getCode();
            }
        }

        /**5.存到redis里面*/
        //5.1把创建的验证码存储到redis中:组装key和code  key:[sms:115251245]  values:[code:时间戳]
        RegisterCodeRedis newCodeRedis = new RegisterCodeRedis(code, System.currentTimeMillis());
        redisTemplate.opsForValue().set(key,newCodeRedis,5, TimeUnit.MINUTES);

        /**6.发送手机验证码*///todo
        //SmsUtils.sendSms(phone,"【源码云课堂】您的验证码是: "+code+",请在5分钟内使用!");
        String content="【源码云课堂】您的注册验证码是: "+code+",请在5分钟内使用!";
        System.out.println(content);
        EmailUtils.sendSms(mobile,code);

        /**7.把短信存到t_message_sms里面*/
        messageSmsService.save("用户注册",content,dto.getMobile());

    }

    /**
     * 创建一个防重token
     * @param courseId
     * @return
     */
    @Override
    public String createToken(Long courseId) {
        //1.参数的校验
        AssertUtil.isNotNull(courseId,"非法请求");
        //2.业务逻辑的校验
        JSONResult jsonResult = courseServerFeign.getCourseByCourseId(courseId);
        AssertUtil.isTrue(jsonResult.isSuccess(),jsonResult.getMessage());
        //把json字符串转为实体对象
        Course course = JSONObject.parseObject(jsonResult.getData().toString(), Course.class);
        AssertUtil.isNotNull(course, "非法请求");
        //校验课程是否发布
        AssertUtil.isEquals(course.getStatus().toString(),Course.ONLINE.toString(),"非法请求");
        //产生token
        String token = StrUtils.getComplexRandomString(30);
        //模拟用户
        Long uid = 3L;

        //存储redis
        String redisKey = String.format(CustomConstant.REDIS_TOKEN_KEY, uid, courseId);
        //把创建的token存放到redis中
        redisTemplate.opsForValue().set(redisKey, token, 30, TimeUnit.MINUTES);

        return token;
    }


}
